import { severities } from 'constants/severities';

// system under test (SUT)
import { getSeverityByCvss, getSeverityCounts, splitCvesByType } from './vulnerabilityUtils';

describe('vulnerabilityUtils', () => {
    describe('getSeverityByCvss', () => {
        it('should return Low constant for a low-level vulnerability', () => {
            const vulnerability = {
                cvss: 2.0999999046325684,
            };

            const severity = getSeverityByCvss(vulnerability.cvss);

            expect(severity).toEqual(severities.LOW_SEVERITY);
        });

        it('should return Low constant for the lower bound of a low-level vulnerability', () => {
            const vulnerability = {
                cvss: 0.1,
            };
            const severity = getSeverityByCvss(vulnerability.cvss);

            expect(severity).toEqual(severities.LOW_SEVERITY);
        });

        it('should return Low constant for the upper bound of a low-level vulnerability', () => {
            const vulnerability = {
                cvss: 3.9,
            };

            const severity = getSeverityByCvss(vulnerability.cvss);

            expect(severity).toEqual(severities.LOW_SEVERITY);
        });

        it('should return Medium constant for a medium-level vulnerability', () => {
            const vulnerability = {
                cvss: 4.0,
            };

            const severity = getSeverityByCvss(vulnerability.cvss);

            expect(severity).toEqual(severities.MEDIUM_SEVERITY);
        });

        it('should return Medium constant for the lower bound of a medium-level vulnerability', () => {
            const vulnerability = {
                cvss: 5,
            };

            const severity = getSeverityByCvss(vulnerability.cvss);

            expect(severity).toEqual(severities.MEDIUM_SEVERITY);
        });

        it('should return Medium constant for the upper bound of a medium-level vulnerability', () => {
            const vulnerability = {
                cvss: 6.9,
            };

            const severity = getSeverityByCvss(vulnerability.cvss);

            expect(severity).toEqual(severities.MEDIUM_SEVERITY);
        });

        it('should return High constant for a high-level vulnerability', () => {
            const vulnerability = {
                cvss: 7.800000190734863,
            };

            const severity = getSeverityByCvss(vulnerability.cvss);

            expect(severity).toEqual(severities.HIGH_SEVERITY);
        });

        it('should return High constant for the lower bound of a high-level vulnerability', () => {
            const vulnerability = {
                cvss: 7.0,
            };

            const severity = getSeverityByCvss(vulnerability.cvss);

            expect(severity).toEqual(severities.HIGH_SEVERITY);
        });

        it('should return High constant for the upper bound of a high-level vulnerability', () => {
            const vulnerability = {
                cvss: 8.9,
            };

            const severity = getSeverityByCvss(vulnerability.cvss);

            expect(severity).toEqual(severities.HIGH_SEVERITY);
        });

        it('should return Critical constant for a critical-level vulnerability', () => {
            const vulnerability = {
                cvss: 9.87654321,
            };

            const severity = getSeverityByCvss(vulnerability.cvss);

            expect(severity).toEqual(severities.CRITICAL_SEVERITY);
        });

        it('should return Critical constant for the lower bound of a critical-level vulnerability', () => {
            const vulnerability = {
                cvss: 9.0,
            };

            const severity = getSeverityByCvss(vulnerability.cvss);

            expect(severity).toEqual(severities.CRITICAL_SEVERITY);
        });

        it('should return Critical constant for the upper bound of a critical-level vulnerability', () => {
            const vulnerability = {
                cvss: 10.0,
            };

            const severity = getSeverityByCvss(vulnerability.cvss);

            expect(severity).toEqual(severities.CRITICAL_SEVERITY);
        });
    });

    describe('getSeverityCounts', () => {
        it('should count the number of critical and critical-fixable vulnerabilities', () => {
            const vulnerabilites = getMockVulnerabilities();

            const counts = getSeverityCounts(vulnerabilites);

            expect(counts[severities.CRITICAL_SEVERITY]).toEqual({ total: 3, fixable: 0 });
        });

        it('should count the number of high and high-fixable vulnerabilities', () => {
            const vulnerabilites = getMockVulnerabilities();

            const counts = getSeverityCounts(vulnerabilites);

            expect(counts[severities.HIGH_SEVERITY]).toEqual({ total: 3, fixable: 1 });
        });

        it('should count the number of medium and medium-fixable vulnerabilities', () => {
            const vulnerabilites = getMockVulnerabilities();

            const counts = getSeverityCounts(vulnerabilites);

            expect(counts[severities.MEDIUM_SEVERITY]).toEqual({ total: 7, fixable: 4 });
        });

        it('should count the number of low and low-fixable vulnerabilities', () => {
            const vulnerabilites = getMockVulnerabilities();

            const counts = getSeverityCounts(vulnerabilites);

            expect(counts[severities.LOW_SEVERITY]).toEqual({ total: 2, fixable: 1 });
        });
    });

    describe('splitCvesByType', () => {
        it('should return empty lists when given an empty array', () => {
            const cves = [];

            const counts = splitCvesByType(cves);

            expect(counts.IMAGE_CVE.length).toEqual(0);
            expect(counts.K8S_CVE.length).toEqual(0);
            expect(counts.OPENSHIFT_CVE.length).toEqual(0);
        });

        it('should return lists with correct members for each type of vulnerability', () => {
            const cves = getMockVulnerabilities();

            const counts = splitCvesByType(cves);

            expect(counts.IMAGE_CVE.length).toEqual(9);
            expect(counts.NODE_CVE.length).toEqual(4);
            expect(counts.K8S_CVE.length).toEqual(3);
            expect(counts.K8S_CVE[0]).toEqual(cves[1]);
            expect(counts.K8S_CVE[1]).toEqual(cves[5]);
            expect(counts.OPENSHIFT_CVE.length).toEqual(2);
            expect(counts.OPENSHIFT_CVE[0]).toEqual(cves[13]);
            expect(counts.OPENSHIFT_CVE[1]).toEqual(cves[14]);
        });
    });
});

function getMockVulnerabilities() {
    return [
        {
            cve: 'CVE-2017-7245',
            cvss: 7.800000190734863,
            isFixable: true,
            vulnerabilityTypes: ['IMAGE_CVE'],
        },
        {
            cve: 'CVE-2018-16869',
            cvss: 5.699999809265137,
            isFixable: true,
            vulnerabilityTypes: ['K8S_CVE'],
        },
        {
            cve: 'CVE-2019-12900',
            cvss: 9.800000190734863,
            isFixable: false,
            vulnerabilityTypes: ['IMAGE_CVE'],
        },
        {
            cve: 'CVE-2010-4052',
            cvss: 3,
            isFixable: true,
            vulnerabilityTypes: ['IMAGE_CVE'],
        },
        {
            cve: 'CVE-2019-12904',
            cvss: 5.900000095367432,
            isFixable: false,
            vulnerabilityTypes: ['IMAGE_CVE'],
        },
        {
            cve: 'CVE-2018-16402',
            cvss: 9.300000190734863,
            isFixable: false,
            vulnerabilityTypes: ['K8S_CVE'],
        },
        {
            cve: 'CVE-2018-18520',
            cvss: 1.5,
            isFixable: false,
            vulnerabilityTypes: ['IMAGE_CVE'],
        },
        {
            cve: 'CVE-2018-16403',
            cvss: 8.5,
            isFixable: false,
            vulnerabilityTypes: ['IMAGE_CVE'],
        },
        {
            cve: 'CVE-2018-1000001',
            cvss: 7.800000190734863,
            isFixable: false,
            vulnerabilityTypes: ['IMAGE_CVE'],
        },
        {
            cve: 'CVE-2018-6551',
            cvss: 4.800000190734863,
            isFixable: true,
            vulnerabilityTypes: ['IMAGE_CVE'],
        },
        {
            cve: 'CVE-2021-12324',
            cvss: 5.0,
            isFixable: false,
            vulnerabilityTypes: ['NODE_CVE'],
        },
        {
            cve: 'CVE-2021-12325',
            cvss: 5.0,
            isFixable: false,
            vulnerabilityTypes: ['NODE_CVE', 'IMAGE_CVE'],
        },
        {
            cve: 'CVE-2021-12326',
            cvss: 5.0,
            isFixable: true,
            vulnerabilityTypes: ['K8S_CVE', 'NODE_CVE'],
        },
        {
            cve: 'CVE-2021-12327',
            cvss: 5.0,
            isFixable: true,
            vulnerabilityTypes: ['OPENSHIFT_CVE', 'NODE_CVE'],
        },
        {
            cve: 'CVE-2021-12328',
            cvss: 9.1,
            isFixable: false,
            vulnerabilityTypes: ['OPENSHIFT_CVE'],
        },
    ];
}
